/*
\ * @(#)CharmGonuAI.java $version 2013. 9. 9.
 *
 */

package com.pace.gonu.ai;

import java.util.ArrayList;
import java.util.List;

import org.apache.commons.lang.StringUtils;
import org.springframework.util.CollectionUtils;

import com.pace.gonu.constants.CharmBoardGroup;
import com.pace.gonu.constants.CharmBoardXY;
import com.pace.gonu.constants.Order;
import com.pace.gonu.constants.Status;
import com.pace.gonu.model.BoardPath;
import com.pace.gonu.model.PlayRock;
import com.pace.gonu.model.chnl.PlayChannel;
import com.pace.gonu.model.rule.CharmPlayRule;
import com.pace.gonu.model.rule.PlayRule;
import com.pace.gonu.model.rule.PlayRuleFactory;
import com.pace.gonu.model.status.PlayStatus;

/**
 * @author pace
 */
public class CharmGonuAI implements GonuAI {
	private List<PlayRock> testPlayRocks = new ArrayList<PlayRock>();


	@Override
	public void play(PlayChannel playChannel) {
		PlayStatus playStatus = playChannel.getPlayStatusObject();
		if (StringUtils.equals(Status.NORMAL.toString(), playStatus.getStatusType())) {
			playNormal(playChannel);
		} else if (StringUtils.equals(Status.MOVE.toString(), playStatus.getStatusType())) {
			playMove(playChannel);
		}
	}

	private void playNormal(PlayChannel playChannel) {
		PlayStatus playStatus = playChannel.getPlayStatusObject();
		
		List<PlayRock> playRocks = playStatus.getPlayRocks();
		List<PlayRock> moveRocks = playStatus.getMoveRocks();
		List<PlayRock> xRocks = playStatus.getXRocks();

		// 참을 만든다.
		CharmBoardGroup selectedGCharmBoardGroup = selectCharmBoardGroup(playRocks, xRocks, Order.RED, 2);
		if (selectedGCharmBoardGroup != null) {
			choiceMoveRock(playRocks, moveRocks, Order.BLUE, selectedGCharmBoardGroup);

			selectedGCharmBoardGroup = selectCharmBoardGroup(playRocks, xRocks, Order.BLUE, 2);
			if (selectedGCharmBoardGroup != null) {
				List<CharmBoardXY> charmBoardXYs = selectedGCharmBoardGroup.getListValues();
				Integer xRockNumber = choiceXRockNumber(playRocks, charmBoardXYs);

				choiceXRock(playChannel, xRockNumber, Order.BLUE.toString());
			} else {
				choiceXRock(playChannel, null, Order.BLUE.toString());
			}

			return;
		}

		// 상대방 참을 박는다.
		selectedGCharmBoardGroup = selectCharmBoardGroup(playRocks, xRocks, Order.BLUE, 2);
		if (selectedGCharmBoardGroup != null) {
			choiceMoveRock(playRocks, moveRocks, Order.BLUE, selectedGCharmBoardGroup);
			return;
		}

		// 참 그룹에 속하는 곳에 둔다. => 보류 
		selectedGCharmBoardGroup = selectCharmBoardGroup(playRocks, xRocks, Order.RED, 1);
		if (selectedGCharmBoardGroup != null) {
			choiceMoveRock(playRocks, moveRocks, Order.BLUE, selectedGCharmBoardGroup);
			return;
		}
		
		int moveRockNumber = (int)(Math.random() * moveRocks.size());
		PlayRock playRock = moveRocks.get(moveRockNumber);
		playRock.setOrder(Order.BLUE);
		playRocks.add(playRock);
		moveRocks.remove(moveRockNumber);

		CharmPlayRule charmPlayRule = new CharmPlayRule();
		if (charmPlayRule.isMove(playStatus)) {
			playStatus.setStatusType(Status.MOVE);
			playStatus.getXRocks().clear();
		}
		// 
	}
	
	/**
	 * xRockNumber가 null 이면 orderStr에 위해서 상배편 말 첫번째 것을 지운다.
	 */
	public void choiceXRock(PlayChannel playChannel, Integer xRockNumber, String orderStr) {
		PlayStatus playStatus = playChannel.getPlayStatusObject();

		int removeRockNumber =0;
		for (PlayRock xRock : playStatus.getPlayRocks()) {
			if (xRockNumber == null && !xRock.getOrder().equals(orderStr)) {
				playStatus.getXRocks().add(xRock);
				playStatus.getPlayRocks().remove(xRock);
				break;
			}

			if (xRockNumber != null && removeRockNumber == xRockNumber) {
				playStatus.getXRocks().add(xRock);
				playStatus.getPlayRocks().remove(xRock);
				break;
			}

			removeRockNumber++;
		}

		playStatus.setStatusType(Status.NORMAL);

		PlayRule playRule = PlayRuleFactory.getInstance(playChannel.getGameTypeObject());
		if (playRule.isMove(playStatus)) {
			playStatus.setStatusType(Status.MOVE);
			playStatus.getXRocks().clear();
		}

	}

	private Integer choiceXRockNumber(List<PlayRock> playRocks, List<CharmBoardXY> charmBoardXYs) {
		for (CharmBoardXY charmBoardXY : charmBoardXYs) {
			int xRockNumber = 0;
			for (PlayRock playRock : playRocks) {
				if (charmBoardXY.getX() == playRock.getPath().getX() && charmBoardXY.getY() == playRock.getPath().getY()) {
					return xRockNumber;
				}
				xRockNumber++;
			}
		}
		return null;
	}

	private void choiceMoveRock(List<PlayRock> playRocks, List<PlayRock> moveRocks, Order order, CharmBoardGroup selectedGCharmBoardGroup) {
		List<CharmBoardXY> charmBoardXYs = selectedGCharmBoardGroup.getListValues();

		for (CharmBoardXY charmBoardXY : charmBoardXYs) {
			for (PlayRock moveRock : moveRocks) {
				if (charmBoardXY.getX() == moveRock.getPath().getX() && charmBoardXY.getY() == moveRock.getPath().getY()) {
					moveRock.setOrder(order);
					playRocks.add(moveRock);
					moveRocks.remove(moveRock);
					return;
				}
			}
		}
	}

	/**
	 * 파라미터 order의 반대돌의 
	 * 참이 될수 잇는 boardPath group 을 반환한다. 
	 */
	private CharmBoardGroup selectCharmBoardGroup(List<PlayRock> playRocks, List<PlayRock> xRocks, Order order, int count) {
		for (PlayRock playRock : playRocks) {
			if (order.equals(playRock.getOrderObject())) {
				continue;
			}

			List<CharmBoardGroup> charmBoardGroups = CharmBoardGroup.getIncludeGroup(playRock.getPath().getX(), playRock.getPath().getY());
			for (CharmBoardGroup charmBoardGroup : charmBoardGroups) {
				List<CharmBoardXY> charmBoardXYs = charmBoardGroup.getListValues();

				boolean isValid = isValidationCharmBoardGroup(playRocks, xRocks, charmBoardGroup, playRock.getOrderObject());

				if (!isValid) {
					continue;
				}

				int result = 0;
				for (CharmBoardXY charmBoardXY : charmBoardXYs) {

					

					for (PlayRock rock : playRocks) {
						if (!playRock.getOrderObject().equals(rock.getOrderObject())) {
							continue;
						}

						if (charmBoardXY.getX() == rock.getPath().getX() && charmBoardXY.getY() == rock.getPath().getY()) {
							result++;
						}
					}
				}

				if (result == count && validationCharmBoardGroup(playRocks, charmBoardGroup, order)) {
					return charmBoardGroup;
				}
			}

		}
		return null;
	}

	/**
	 * xRock이나 유저의 돌이 들어있는지 확인
	 */
	private boolean isValidationCharmBoardGroup(List<PlayRock> playRocks, List<PlayRock> xRocks, CharmBoardGroup charmBoardGroup, Order order) {

		for (CharmBoardXY charmBoardXY : charmBoardGroup.getListValues()) {

			for (PlayRock xRock : xRocks) {
				if (xRock.getPath().getX() == charmBoardXY.getX() && xRock.getPath().getY() == charmBoardXY.getY()) {
					return false;
				}
			}


			// 유저의 돌이 포함되어 있으면 제외
			for (PlayRock rock : playRocks) {
				if (order.equals(rock.getOrderObject())) {
					continue;
				}
				if (rock.getPath().getX() == charmBoardXY.getX() && rock.getPath().getY() == charmBoardXY.getY()) {
					break;
				}
			}
		}
		return true;
	}

	private boolean validationCharmBoardGroup(List<PlayRock> playRocks, CharmBoardGroup charmBoardGroup, Order order) {
		for (PlayRock playRock : playRocks) {
			if (!order.equals(playRock.getOrderObject())) {
				continue;
			}

			List<CharmBoardXY> charmBoardXYs = charmBoardGroup.getListValues();
			int result = 0;
			for (CharmBoardXY charmBoardXY : charmBoardXYs) {
				for (PlayRock rock : playRocks) {
					if (!playRock.getOrderObject().equals(rock.getOrderObject())) {
						continue;
					}

					if (charmBoardXY.getX() == rock.getPath().getX() && charmBoardXY.getY() == rock.getPath().getY()) {
						result++;
					}
				}
			}

			if (result > 0) {
				return false;
			}
		}

		return true;
	}


	private void playMove(PlayChannel playChannel) {

		PlayStatus playStatus = playChannel.getPlayStatusObject();
		List<PlayRock> playRocks = playStatus.getPlayRocks();
		List<PlayRock> tempRocks = new ArrayList<PlayRock>();
		tempRocks.addAll(playRocks);
		PlayRule rule = PlayRuleFactory.getInstance(playChannel.getGameTypeObject());
		
		// charm 이 되는 것에 놓는다
		for (PlayRock testRock : tempRocks) {
			if (testRock.getOrderObject().equals(Order.RED)) {
				continue;
			}

			List<BoardPath> boardPaths = rule.getMovePath(playStatus.getPlayRocks(), testRock);
			
			for (BoardPath boardPath : boardPaths) {
				PlayRock tempRock = new PlayRock();
				tempRock.setPath(testRock.getPath());
				
				testRock.setPath(boardPath);

				if (rule.isCharm(playStatus.getPlayRocks(), testRock)) {
					for (PlayRock playRock : playRocks) {
						if (playRock.eqaul(testRock)) {
							playRock.setPath(testRock.getPath());

							CharmBoardGroup selectedGCharmBoardGroup = selectCharmBoardGroup(playRocks, new ArrayList<PlayRock>(), Order.BLUE, 2);
							if (selectedGCharmBoardGroup != null) {
								List<CharmBoardXY> charmBoardXYs = selectedGCharmBoardGroup.getListValues();

								Integer xRockNumber = choiceXRockNumber(playRocks, charmBoardXYs);
								if (xRockNumber == null) {
									throw new IllegalStateException("xRock 선정에 문제가 있었습니다. 처음부터 다시 시작해주세요");
								}

								choiceXRock(playChannel, xRockNumber, Order.BLUE.toString());
							}
							return;
						}
					}
				}
				// 
				testRock.setPath(tempRock.getPath());

			}

		}
		
		// 상대밥 참이 될 수 있는 곳을 막는다
		List<BoardPath> boardPaths = new ArrayList<BoardPath>();

		//상대방 참이 되는 곳을 찾는다.
		for (PlayRock testRock : tempRocks) {
			if (testRock.getOrderObject().equals(Order.BLUE)) {
				continue;
			}
			
			
			List<BoardPath> redboardPaths = rule.getMovePath(playStatus.getPlayRocks(), testRock);
			//레드의 참이 될 수 있는 경로를 찾음
			for (BoardPath redboardPath : redboardPaths) {
				PlayRock tempRock = new PlayRock();
				tempRock.setPath(testRock.getPath());

				testRock.setPath(redboardPath);
				PlayRule playRule = PlayRuleFactory.getInstance(playChannel.getGameTypeObject());

				if (playRule.isCharm(playStatus.getPlayRocks(), testRock)) {
					boardPaths.add(redboardPath);
				}
				// 
				testRock.setPath(tempRock.getPath());
			}
		}

		//레드의 참을 막을 수 있는 돌을 찾는다.
		for (PlayRock testRock : tempRocks) {
			if (testRock.getOrderObject().equals(Order.RED)) {
				continue;
			}

			List<BoardPath> blueboardPaths = rule.getMovePath(playStatus.getPlayRocks(), testRock);

			for (BoardPath blueBoardPath : blueboardPaths) {
				for (BoardPath boardPath : boardPaths) {
					if (blueBoardPath.equal(boardPath)) {
						for (PlayRock playRock : playRocks) {
							if (playRock.eqaul(testRock)) {
								playRock.setPath(boardPath);
								return;
							}
						}
					}
				}

			}
		}

		//		 아무 그룹이나 선택 . 1
		int blueRockCount = 0;
		for (PlayRock playRock : playRocks) {
			if (playRock.getOrderObject().equals(Order.BLUE)) {
				List<BoardPath> blueboardPaths = rule.getMovePath(playStatus.getPlayRocks(), playRock);
				if (!CollectionUtils.isEmpty(blueboardPaths)) {
					blueRockCount++;
				}
			}

		}

		int rndSelectIndex = (int)(Math.random() * blueRockCount);

		for (PlayRock playRock : playRocks) {
			if (playRock.getOrderObject().equals(Order.RED)) {
				continue;
			}

			List<BoardPath> blueboardPaths = rule.getMovePath(playStatus.getPlayRocks(), playRock);
			if (!CollectionUtils.isEmpty(blueboardPaths)) {
				if (0 == rndSelectIndex--) {
					playRock.setPath(blueboardPaths.get(0));
					return;
				}
			}
		}



		// 아무 지점이나 놓는다. 2
		//		for (PlayRock playRock : playRocks) {
		//			if (playRock.getOrderObject().equals(Order.RED)) {
		//				continue;
		//			}
		//
		//			List<BoardPath> blueboardPaths = rule.getMovePath(playStatus.getPlayRocks(), playRock);
		//			if (!CollectionUtils.isEmpty(blueboardPaths)) {
		//				int pathNumber = (int)(Math.random() * blueboardPaths.size());
		//				playRock.setPath(blueboardPaths.get(pathNumber));
		//				return;
		//			}
		//		}
	}
}
